home *** CD-ROM | disk | FTP | other *** search
/ Network Supervisor's Toolkit / Network Supervisor's Toolkit.iso / tools / nwtp06 / nwconn.pas < prev    next >
Pascal/Delphi Source File  |  1996-07-10  |  49KB  |  1,456 lines

  1. {$X+,B-,V-,S-} {essential compiler directives}
  2.  
  3. UNIT nwConn;
  4.  
  5. { nwConn unit as of 950301 / NwTP 0.6 API. (c) 1993,1995, R. Spronk }
  6. { Includes modifications to Attach/Detach by H. Jelonneck           }
  7.  
  8. INTERFACE
  9.  
  10. { Primary Functions:                    Interrupt: comments:
  11.  
  12. Connection Services
  13. -------------------
  14.  
  15. * AttachToFileServer                    (F100)
  16. * AttachToFileServerWithAddress         (F100)
  17. * DetachFromFileServer                  (F101)
  18. . EnterLoginArea                        (F217/0A)
  19. * GetConnectionInformation              (F217/16)
  20. * GetConnectionNumber                   (DC..)
  21. * GetInternetAddress                    (F217/13)
  22. * GetObjectConnectionNumbers            (F217/15)
  23. * GetWorkstationNodeAddress             (EE..)
  24. * LoginToFileserver                     (F217/14) UNencrypted
  25. * LoginEncrToFileserver                 (F217/18) encrypted
  26. * Logout                                (F219)
  27. * LogoutFromFileServer                  (F102)
  28.  
  29.   Secondary Functions:
  30.  
  31. * GetUserAtConnection
  32. * GetObjectLoginControl
  33. * GetObjectNodeControl
  34. * ObjectCanLoginAt
  35.  
  36. Workstation Services
  37. --------------------
  38.  
  39. * EndOfJob                              (D6)         to be rewritten to F218
  40. * GetConnectionID                       (EF04)
  41. * GetConnectionIDtable                  (EF03)       (1)
  42. * GetDefaultConnectionID                (F002)
  43. * GetEndOfJobStatus                     (BB..)
  44. * GetFileServerName                     (EF04)
  45. * GetNetwareErrorMode                   (DD..)
  46. * GetNetwareShellVersion                (EA00)
  47. * GetNumberOfLocalDrives                (DB..)
  48. * GetPreferredConnectionID              (F001)
  49. * GetPrimaryConnectionID                (F005)
  50. * GetShowDots                           (E908)
  51. * GetWorkstationEnvironment             (EAxx,xx>00) (2)
  52. * SetEndOfJobStatus                     (BB..)
  53. * SetNetwareErrorMode                   (DD..)
  54. * SetPreferredConnectionID              (F000)
  55. * SetPrimaryConnectionID                (F004)
  56. * SetShowDots                           (E908)
  57.  
  58.   Secondary Functions:
  59.  
  60. * GetEffectiveConnectionID              (F001,F002,F005)
  61. * IsConnectionIDinUse                   (EF03)
  62.  
  63.  
  64. Not Implemented:
  65. ----------------
  66.  
  67. - GetStationsLoggedInformation          (F217/05) (3)
  68. - Login                                 (F217/00) (4)
  69. - MapUserToStationSet                   (F217/02) (5)
  70.  
  71. Notes: -Only functions marked with a * have been tested; others might work.
  72.        -(1): This function returns the complete Connection ID table. The
  73.              partial function IsConnectionIDInUse has been moved to the
  74.              secondary function group.
  75.        -(2): This function is an extension to EA00 GetNetwareShellVersion.
  76.              A function that returns all returned information from the call
  77.              EAxx,xx>00 is sometimes referred to as GetWShardwareAndOS.
  78.  
  79.        -NOT implemented in this API:
  80.         (3): Replaced by F217/16 GetConnectionInformation.
  81.         (4): This function has been replaced by F217/14 LoginToFileServer.
  82.         (5): Replaced by F217/15 GetObjectConnectionNumbers.
  83.  
  84.        -NW 386 can support up to 250 connections, NW 286 Max 100.
  85.        -Type TconnectionList=array[1..250] of byte (Declared in unit nwMisc)
  86.  
  87. }
  88.  
  89. Uses nwIntr,nwMisc,nwBindry;
  90.  
  91.  
  92. Const MaxServers=8;
  93.  
  94. Type TServerNameTableEntry = Array [1..48] OF Char;
  95.      TServerNameTable = Array[1..MaxServers] OF TServerNameTableEntry;
  96.  
  97.      TConnectionIDTableEntry=
  98.        Record
  99.        SlotInUse        : Byte;
  100.        OrderNumber      : Byte;
  101.        ServerAddress    : TinternetworkAddress;
  102.        ReceiveTimeOut   : Word;
  103.        RouterAddress    : TnodeAddress;
  104.        PacketSeqNbr     : Byte;
  105.        ConnectionNumber : Byte;
  106.        ConnectionStatus : Byte;
  107.        MaxTimeOut       : Word;
  108.        WConnectionNumber: Word;
  109.        MajorNWrev       : Byte;
  110.        ServerFlags      : Byte;
  111.        MinorNWrev       : Byte;
  112.        END;
  113.      TConnectionIDTable = Array [1..MaxServers] OF TConnectionIDTableEntry;
  114.  
  115.      TloginControl=Record
  116.                    AccountDisabled           :boolean;
  117.                    AccountExpirationDate     :TNovTime; { dmy valid only }
  118.  
  119.                    MinimumPasswordLength     :byte;
  120.                    PasswordControlFlag       :byte;
  121.                    DaysBetweenPasswordChanges:word;
  122.                    PasswordExpirationDate    :TnovTime;
  123.                    LastLoginTime             :TnovTime; {dmy, hms valid only }
  124.                    GraceLoginsRemaining      :Byte;
  125.                    MaxGraceLoginsAllowed     :byte;
  126.                    BadLoginCount             :byte;
  127.                    AccountResetTime          :TnovTime; {dmy, hms valid only }
  128.                    LastIntruderAddress       :TinterNetworkAddress;
  129.  
  130.                    MaxConcurrentConnections  :byte;
  131.                    LoginTimes                :array[1..42] of byte;
  132.  
  133.                    DiskSpace                 :Longint;
  134.                    end;
  135.  
  136.      TnodeControl=array[1..12] of record
  137.                                   net :TnetworkAddress;
  138.                                   node:TnodeAddress;
  139.                                   end;
  140.  
  141. Var result:word;
  142.  
  143. {BB.. [2.0/2.1/3.x]}
  144. Function SetEndOfJobStatus( EndOfJobFlag: Boolean ):Boolean;
  145. { When this function is called with EndOfJobFlag=False and control is returned
  146.   to the root COMMAND.COM, COMMAND.COM will NOT perform an EOJ action.     }
  147.  
  148. {BB.. [2.0/2.1/3.x]}
  149. Function GetEndOfJobStatus(Var EndOfJobFlag: Boolean ):Boolean;
  150.  
  151. {F218 [2.15c+]}
  152. FUNCTION EndOfJob(All : Boolean):boolean;
  153. { Forces an end of job }
  154.  
  155. {E908 (shell 3.00+)}
  156. Function SetShowDots( Show:Boolean):Boolean;
  157.  
  158. {E908 (shell 3.00+)}
  159. Function GetShowDots(Var Shown:Boolean):Boolean;
  160.  
  161. {F219 [2.15c+]}
  162. Function Logout:boolean;
  163. { Logout from all file servers, remains attached to Server, effective EOJ }
  164.  
  165. {DB.. [2.0/2.1/3.x]}
  166. Function GetNumberOfLocalDrives( Var drives:Byte ):Boolean;
  167.  
  168. {DC.. [2.0/2.1/3.x]}
  169. Function GetConnectionNumber(Var ConnectionNbr:byte):boolean;
  170. { Returns connection number of requesting WS }
  171.  
  172. {DD.. [2.0/2.1/3.x]}
  173. Function SetNetwareErrorMode( errMode:Byte):boolean;
  174. { Sets the shell's handling mode for dealing with netware errors. }
  175.  
  176. {DD.. [2.0/2.1/3.x]}
  177. Function GetNetwareErrorMode(Var errMode:Byte):boolean;
  178.  
  179. {E3../0A [2.0/2.1/3.x]}
  180. Function EnterLoginArea( LoginSubDirName:String;
  181.                          numberOfLocalDrives:Byte ):boolean;
  182. { Changes the login directory. Used by boot-proms. }
  183.  
  184. {F217/13 [2.15c+]}
  185. Function GetInternetAddress( ConnNbr : byte;
  186.                          var IntNetAddress:TinternetworkAddress):boolean;
  187.  
  188. {F217/14 [2.15c+] UNENCRYPTED}
  189. Function LoginToFileServer( objName:String; objType:word;
  190.                             password : string              ):boolean;
  191.  
  192. {F217/18 [2.15c+] ENCRYPTED}
  193. FUNCTION LoginEncrToFileServer(ObjName: String; ObjType: Word;
  194.                                PassWord: String            ): Boolean;
  195.  
  196. {F217/15 [2.15c+]}
  197. Function GetObjectConnectionNumbers( objName:String; objType:Word;
  198.                                      Var numberOfConnections: Byte;
  199.                                      Var connections: TconnectionList ):boolean;
  200. { returns a list of connectionnumbers where objects of the desired type and
  201.   name are logged in. }
  202.  
  203. {F217/16 [2.15c+]}
  204. Function GetConnectionInforMation (ConnectionNbr:byte;
  205.                                    Var objName:String;
  206.                                    Var objType:Word;
  207.                                    Var objId:LongInt;
  208.                                    Var LoginTime:TnovTime ):boolean;
  209.  
  210. {EA00 [2.0/2.1/3.x]}
  211. Function GetNetwareShellVersion( Var MajorVersion,MinorVersion,
  212.                                      RevisionLevel :Byte       ):Boolean;
  213. { Returns information about a WS environment. Queries shell. }
  214.  
  215. {EAxx,xx>00 [2.0/2.1/3.x]}
  216. Function GetWorkstationEnvironment(Var OStype,OSversion,
  217.                               HardwareType,ShortHWType:String):Boolean;
  218.  
  219. {EE.. [2.0/2.1/3.x]}
  220. FUNCTION GetWorkstationNodeAddress( var physicalNodeAddress: TNodeAddress ):boolean;
  221. { Get the physical address of the workstation (6 bytes hi-endian) }
  222.  
  223.  
  224. {EF03 [2.0/2.1/3.x]}
  225. Function GetConnectionIDTable( ConnectionID: Byte ; Var TableEntry: TConnectionIDTableEntry ):boolean;
  226. { Returns a copy of the entry in the shells' ConnectionID table corresponding
  227.   with the given ConnectionID. }
  228.  
  229. {EF04 [2.0/2.1/3.x]}
  230. Function GetConnectionID( serverName: String; Var ConnectionID: Byte):boolean;
  231.  
  232.  
  233. {EF04 [2.0/2.1/3.x]}
  234. Function GetFileServerName( ConnectionID : byte; var ServerName : string):boolean;
  235. { get name of file server. file server number must be in range [1..MaxServers] }
  236.  
  237. {F000 [2.0/2.1/3.x]}
  238. Function SetPreferredConnectionID( ConnectionID :byte ):boolean;
  239.  
  240. {F001 [2.0/2.1/3.x]}
  241. Function GetPreferredConnectionID(var connID : byte):boolean;
  242.  
  243. {F002 [2.0/2.1/3.x]}
  244. FUNCTION GetDefaultConnectionID(var connID :byte):boolean;
  245.  
  246. {F004 [2.0/2.1/3.x]}
  247. FUNCTION SetPrimaryConnectionID( primaryConnectionID :Byte ):boolean;
  248.  
  249. {F005 [2.0/2.1/3.x]}
  250. FUNCTION GetPrimaryConnectionID(var connID :byte ):boolean;
  251.  
  252. {F100 [2.0+]}
  253. Function AttachToFileServerWithAddress(ServerName:string;
  254.                                        ServerAddr:TinternetworkAddress;
  255.                                        Var ConnectionID:Byte):Boolean;
  256.  
  257. {F100 [2.0/2.1/3.x] (also calls EF03,EF04)}
  258. Function AttachToFileServer(ServerName : String; Var ConnectionID:Byte):Boolean;
  259. { Create an attachment between a server and a workstation. }
  260.  
  261. {F101 [2.0/2.1/3.x]}
  262. Function DetachFromFileServer( ConnectionID:byte ):boolean;
  263. { removes server from shell's server table. Relinquishes the
  264.   fileserver connection number and breaks the connection.         }
  265.  
  266. {F102 [2.0/2.1/3.x]}
  267. Function LogoutFromFileServer(var ConnectionID: byte):boolean;
  268. {logout from one file server}
  269.  
  270. {***** secondary Functions, Result variable is not used *******************}
  271.  
  272. {EF03 [2.0/2.1/3.x] secondary Function }
  273. Function IsConnectionIDinUse( ConnectionID: Byte ):boolean;
  274.  
  275. Function GetUserAtConnection( ConnectionNbr:byte; var username: string):boolean;
  276. {This function provides a short method of obtaining just the USERID.}
  277.  
  278. Function GetEffectiveConnectionID(Var connId:byte):boolean;
  279. {What server are the requests currently sent to? }
  280.  
  281. Function GetObjectLoginControl(ObjName:string; ObjType:word;
  282.                                VAR LoginControlInfo:TloginControl):boolean;
  283.  
  284. Function GetObjectNodeControl( ObjName:string; ObjType:word;
  285.                               {i/o} Var seqNbr:integer;
  286.                               {out} Var NodeControlInfo:TnodeControl):boolean;
  287.  
  288. Function ObjectCanLoginAt(ObjName:String; ObjType:Word;
  289.                           LoginTime:TnovTime            ):Boolean;
  290. { -If the fields hour,min,sec and dayOfWeek are filled, the time
  291.    will be checked against the login timerestrictions.
  292.   -If the fields year,month,day are filled ( >0 ), the date
  293.    will be checked with the expiration date of the account and
  294.    with the Account disabled Flag. }
  295.  
  296. IMPLEMENTATION{=============================================================}
  297.  
  298. Type TPConnectionIDTPtr=^TConnectionIDTable;
  299.      TPServerNTPtr=^TServerNameTable;
  300.  
  301. {F000 [2.0/2.1/3.x]}
  302. Function SetPreferredConnectionID( ConnectionID :byte ):boolean;
  303. { The preferred server is the default server to which the request
  304.   packets are sent.
  305.   Calls are routed to the preferred server. (IF explicitly set!).
  306.   If the preferred server was not set then the requests are routed to
  307.   the server that is attached to the current drive. If the current
  308.   drive is a local drive then the requests will be sent to the primary
  309.   server (mostly the server the shell initially attached to.)            }
  310. var regs : TTregisters;
  311. begin
  312.  regs.ax := $F000;
  313.  regs.dl := ConnectionID; { 1..MaxServers, 0 to clear }
  314.  RealModeIntr($21,regs);
  315.  result:=0;
  316.  SetPreferredConnectionID:=TRUE;
  317. end;
  318.  
  319. {F004 [2.0/2.1/3.x]}
  320. FUNCTION SetPrimaryConnectionID( primaryConnectionID :Byte ):boolean;
  321. var regs : TTregisters;
  322. begin
  323.  regs.ax := $F004;
  324.  regs.dl := primaryConnectionID; { 1..MaxServers, or 0 to clear }
  325.  RealModeIntr($21,regs);
  326.  result:=0;
  327.  SetPrimaryConnectionID:=TRUE;
  328. end;
  329.  
  330. {F005 [2.0/2.1/3.x]}
  331. FUNCTION GetPrimaryConnectionID(var connID :byte ):boolean;
  332. { returns connection number of the primary file server (1..MaxServers) }
  333. var regs : TTregisters;
  334. begin
  335.  regs.ax := $F005;
  336.  RealModeIntr($21,regs);
  337.  connID := regs.al;
  338.  if connId>MaxServers
  339.   then result:=$FF
  340.   else result:=$00;
  341.  GetPrimaryConnectionID:=(result=0);
  342. end;
  343.  
  344. {F002 [2.0/2.1/3.x]}
  345. FUNCTION GetDefaultConnectionID(var connID :byte):boolean;
  346. { Returns the connection ID of the file server to which
  347.   the packets are currently being sent.                                    }
  348. var regs : TTregisters;
  349. begin
  350.  regs.ax := $F002;
  351.  RealModeIntr($21,regs);
  352.  connID := regs.al; { 1..MaxServers }
  353.  if connId>MaxServers
  354.   then result:=$FF
  355.   else result:=$00;
  356.  GetDefaultConnectionID:=(result=0);
  357. end;
  358.  
  359. {F001 [2.0/2.1/3.x]}
  360. Function GetPreferredConnectionID(var connID : byte):boolean;
  361. var regs : TTregisters;
  362. begin
  363.  regs.ax := $F001;
  364.  RealModeIntr($21,regs);
  365.  connID := regs.al; { 1..MaxServers, or 0 if the preferred server was not set }
  366.  { The preferred coneection is reset to 0 by an EOJ. }
  367.  if connId>MaxServers
  368.   then result:=$FF
  369.   else result:=$00;
  370.  GetPreferredConnectionID:=(result=0);
  371. end;
  372.  
  373.  
  374.  
  375. {EF04 [2.0/2.1/3.x]}
  376. Function GetConnectionID( serverName: String; Var ConnectionID: Byte):boolean;
  377. Type ptarr=^arr;
  378.      arr=Array[0..MaxServers*32] of Byte;
  379. Var regs       : TTregisters;
  380.     NameTable  : Array [1..MaxServers*48] of Byte;
  381.     ServerNames: Array [1..MaxServers] of String;
  382.     t          : Byte;
  383. begin
  384. UpString(ServerName);
  385. regs.ax := $EF04;
  386. RealModeIntr($21,regs);
  387. { get pointer to shell's server name table. }
  388. move(nwPtr(regs.es, regs.si)^,NameTable,MaxServers*48);
  389. For t := 0 to 7
  390.   do ZstrCopy(ServerNames[t+1],NameTable[1+ t*48],48);
  391.  
  392. t:=1;
  393. While ((t<9) and (ServerNames[t]<>ServerName))
  394.  do inc(t);
  395. If t=9
  396.  then Result:=$FC { invalid server name }
  397.  else begin
  398.       ConnectionID:=t;
  399.       { ServerName found. Is ConnectionID valid ? }
  400.       regs.ax:=$EF03;
  401.       RealModeIntr($21,regs);
  402.       IF (ptarr(nwPtr(regs.es,regs.si))^[(ConnectionID-1)*32] = $00 ) {= $FF ?? }
  403.        then begin
  404.             ConnectionID:=0;
  405.             result:=$FC { ConnectionID invalid => servername invalid }
  406.             end
  407.        else result:=$00;
  408.       end;
  409. GetConnectionID:=(result=0);
  410. end;
  411.  
  412.  
  413. {EF04 [2.0/2.1/3.x]}
  414. Function GetFileServerName( ConnectionID : Byte; Var ServerName : String):boolean;
  415. { Get the name of file server, associated with the ConnectionID.
  416.   The File server number must be in the range [1..MaxServers].
  417.   The function will fail (result=$FF) if connID falls outside of this range. }
  418. Type ptarr=^arr;
  419.      arr=Array[0..MaxServers*32] of Byte;
  420. Var regs       : TTregisters;
  421.     NameTable  : Array [1..MaxServers*48] of Byte;
  422.     ServerNames: Array [1..MaxServers] of String;
  423.     t          : Byte;
  424. begin
  425. regs.ax := $EF04;
  426. RealModeIntr($21,regs);
  427. { Get pointer to shell's server name table. }
  428. move(nwPtr(regs.es, regs.si)^,NameTable,MaxServers*48);
  429. For t := 0 to 7
  430.   do ZstrCopy(ServerNames[t+1],NameTable[1+ t*48],48);
  431.  
  432. if ((ConnectionID<1) or (ConnectionID>MaxServers))
  433.   then ServerName:=''
  434.   else ServerName := ServerNames[ConnectionID];
  435. IF ServerName=''
  436.  then result:=$FF
  437.  else begin { The name is valid, but is the ConnectionID valid ? }
  438.       regs.ax:=$EF03;
  439.       RealModeIntr($21,regs);
  440.       IF (ptarr(nwPtr(regs.es,regs.si))^[(ConnectionID-1)*32] = $00 ) {= $FF ?? }
  441.        then begin
  442.             result:=$FF; { ConnectionID invalid => servername invalid }
  443.             ServerName:='';
  444.             end
  445.        else result:=$00;
  446.       end;
  447. GetFileServerName:=(result=0);
  448. end;
  449.  
  450.  
  451. Function AttachToFileServerWithAddress(ServerName:string;
  452.                                        ServerAddr:TinternetworkAddress;
  453.                                        Var ConnectionID:Byte):Boolean;
  454. { Create an attachment between a server and a workstation. }
  455. { Does not Login the workstation. }
  456. { After attaching, and beFore logging in, you must set the preferred server
  457.   to the ConnectionID of the server. }
  458. { Will not report an error if you're already attached to
  459.  -or even logged on to- the target server. }
  460. { Attaches to the server whose address is supplied. The server name will
  461.   be placed in the server name tables, even if the servername is incorrect or
  462.   the supplied servername isn't associated with the supplied address. }
  463. { Based on the InsertServer Function in LOGON.PAS by Barry Nance, and
  464.   on Rose, p.262 }
  465. Var  ConnectionIDTPtr : TPConnectionIDTPtr;
  466.      ServerNTPtr      : TPServerNTPtr;
  467.      NewServerSlot,i  : Byte;
  468.      OldConnId        : Byte;
  469.      ServIsAttached   : Boolean;
  470.      AccessLevel      : Byte;
  471.      ObjID            : Longint;
  472.  
  473.      Regs:TTRegisters;
  474.  
  475.      NewServer:Boolean;
  476.  
  477.      Var cid:byte;
  478.  
  479. BEGIN
  480. { If server known, take adress from shells' tables.
  481.   If server not known, try to read its' adress from a servers' bindery.
  482.   This will fail if you're not connected to at least one server.
  483.   Once an adress has been found, AttachToFileServerWithAdress is called. }
  484.  
  485. ServerAddr.socket:=swap($0451); { swapped hi-lo}
  486. UpString(ServerName);
  487.  
  488. regs.ax:=$EF03;
  489. RealModeIntr($21,regs);
  490. ConnectionIDTPtr:=nwPtr(regs.es,regs.si); { Ptr to TConnectionIDTable }
  491.  
  492. { Determine whether the suplied server is already known/attached to }
  493.  
  494. ConnectionID:=0;
  495. REPEAT
  496.  inc(ConnectionID)
  497. UNTIL (ConnectionID>MaxServers)
  498.       or ((ConnectionIDTPtr^[ConnectionID].SlotInUse>0)
  499.           and IsEqualNetworkAddress(ConnectionIDTPtr^[ConnectionID].ServerAddress,ServerAddr)
  500.          );
  501.  
  502. NewServer:=(ConnectionID>MaxServers);
  503.  
  504. { If the server is a new server, put it in the sorted ConnectionIDTable }
  505. IF NewServer
  506.  then begin
  507.       { Determine free slot to insert new server }
  508.       NewServerSlot := 1;
  509.       WHILE (ConnectionIDTPtr^[NewServerSlot].SlotInUse <> $00)
  510.             AND (NewServerSlot <= MaxServers)
  511.         do inc(NewServerSlot);
  512.       IF NewServerSlot > MaxServers
  513.        then begin
  514.             Result:=$7C;
  515.             AttachToFileServerWithAddress := False;
  516.             exit;
  517.             end;
  518.  
  519.       With ConnectionIDTPtr^[NewServerSlot]
  520.        do begin
  521.           ServerAddress:=ServerAddr;
  522.           OrderNumber := 0;
  523.           For i := 1 TO MaxServers
  524.            do begin
  525.               IF (ConnectionIDTPtr^[i].SlotInUse <> $00)
  526.                  and (ConnectionIDTPtr^[i].OrderNumber>=OrderNumber)
  527.                then OrderNumber:=ConnectionIDTPtr^[i].OrderNumber+1;
  528.               end;
  529.           SlotInUse := $FF; { Must be set to $FF before attaching }
  530.           end;
  531.       ConnectionID:=NewServerSlot;
  532.       end
  533.  else { NOT a new server.. }
  534.       IF (ConnectionIDTPtr^[ConnectionID].ConnectionNumber > 0)
  535.           AND (ConnectionIDTPtr^[ConnectionID].ConnectionNumber < $FF)
  536.           AND (ConnectionIDTPtr^[ConnectionID].ConnectionStatus = $FF)
  537.        then Begin { ServerIsKnown }
  538.             GetPreferredConnectionID (OldConnId);
  539.             SetPreferredConnectionID (ConnectionID);
  540.             ServIsAttached := GetBinderyAccessLevel (AccessLevel, ObjID);
  541.             SetPreferredConnectionID (OldConnID);
  542.             IF ServIsAttached  { ServerIsAlreadyAttached / caller may even be looged on }
  543.              then begin
  544.                   result:=0;
  545.                   AttachToFileServerWithAddress := True;
  546.                   exit;
  547.                   end;
  548.             End;
  549.  
  550. { Create an attachment }
  551. With Regs
  552. do begin
  553.    AX := $F100;
  554.    DL := ConnectionID;
  555.    RealModeIntr($21,Regs);
  556.    Result := AL;
  557.    { F8 already attached to server; F9 No Free connection slots at server;
  558.      FA no more server slots;       FE Server Bindery Locked;
  559.      FF No response from server }
  560.    end;
  561.  
  562. IF NewServer
  563.  then begin
  564.       if Result<>$00 { F9/FA/FE/FF error at server/no response from server }
  565.        then Begin    { Note that the combination of a 'new' server and err. F8 is impossible }
  566.             ConnectionIDTPtr^[NewServerSlot].SlotInUse:=$00;
  567.             { Invalid server, Free slot again }
  568.             end
  569.        else begin
  570.             { Valid server, sort ConnectionID table }
  571.             With ConnectionIDTPtr^[NewServerSlot]
  572.              do begin
  573.                 SlotInUse:=$00; { temporarily set to 0, For sorting purposes }
  574.                 OrderNumber := 1;
  575.                 For i := 1 TO MaxServers
  576.                  do begin
  577.                     IF ConnectionIDTPtr^[i].SlotInUse <> $00
  578.                      then begin
  579.                           IF IsLowerNetworkAddress(ConnectionIDTPtr^[i].ServerAddress, ServerAddress)
  580.                            then inc(OrderNumber)
  581.                            else inc(ConnectionIDTPtr^[i].OrderNumber)
  582.                           end;
  583.                     end;
  584.                 SlotInUse:=$FF;
  585.                 end;
  586.             { Put new servers' name in server Name Table }
  587.             regs.ax := $EF04;
  588.             RealModeIntr($21,regs);
  589.             ServerNTPtr:=nwPtr(regs.es, regs.si); { pointer to shell's server name table. }
  590.             FillChar(ServerNTPtr^[NewServerSlot],48,#0);
  591.             If ServerName[0]>#47
  592.             then ServerName[0]:=#47;
  593.             Move(ServerName[1],ServerNTPtr^[NewServerSlot],Length (ServerName));
  594.             end;
  595.       end;
  596.  
  597. AttachToFileServerWithAddress:=(result=0);
  598. { Valid completion codes:
  599.   7C Maximum number of attached servers exceeded.
  600.   F8 already attached to server;
  601.   F9 No Free connection slots at specified server;
  602.   FA no more server slots;
  603.   FF No response from server
  604.   FC No Free slots in shells' ConnectionID table; }
  605. end;
  606.  
  607.  
  608. Function AttachToFileServer(ServerName : String; Var ConnectionID:Byte):Boolean;
  609. { Create an attachment between a server and a workstation. }
  610. { !! you have to be attached to at least 1 server before calling this function. }
  611. { Does not Login the workstation. }
  612. { After attaching, and beFore logging in, you must set the preferred server
  613.   to the ConnectionID of the server. }
  614. { Will not report an error if you're already attached to
  615.  -or even logged on to- the target server. }
  616. Var  ConnectionIDTPtr : TPConnectionIDTPtr;
  617.      OldConnId        : Byte;
  618.      ServIsAttached   : Boolean;
  619.      AccessLevel      : Byte;
  620.      ObjID            : Longint;
  621.  
  622.      PropValue        :Tproperty;
  623.      MoreSegments     :boolean;
  624.      PropFlags        :Byte;
  625.  
  626.      Regs:TTRegisters;
  627.  
  628.      ServAddr:TinternetworkAddress;
  629. BEGIN
  630. { If server known, take adress from shells' tables.
  631.   If server not known, try to read its' address from a servers' bindery.
  632.   This will fail if you're not connected to at least one server.
  633.   Once an adress has been found, AttachToFileServerWithAdress is called. }
  634. UpString(ServerName);
  635.  
  636. regs.ax:=$EF03;
  637. RealModeIntr($21,regs);
  638. ConnectionIDTPtr:=nwPtr(regs.es,regs.si); { Ptr to TConnectionIDTable }
  639.  
  640. { Determine whether the suplied server is already known/attached to }
  641. IF GetConnectionID(ServerName,ConnectionID)
  642.  then Begin
  643.       IF (ConnectionIDTPtr^[ConnectionID].ConnectionNumber > 0)
  644.          AND (ConnectionIDTPtr^[ConnectionID].ConnectionNumber < $FF)
  645.          AND (ConnectionIDTPtr^[ConnectionID].ConnectionStatus = $FF)
  646.        then Begin { ServerIsKnown }
  647.             GetPreferredConnectionID (OldConnId);
  648.             SetPreferredConnectionID (ConnectionID);
  649.             ServIsAttached := GetBinderyAccessLevel (AccessLevel, ObjID);
  650.             SetPreferredConnectionID (OldConnID);
  651.             result:=0;
  652.             IF ServIsAttached  { ServerIsAlreadyAttached / caller may even be looged on }
  653.              then begin
  654.                   AttachToFileServer := True;
  655.                   exit;
  656.                   end
  657.              else ServAddr:=ConnectionIDTPtr^[ConnectionID].ServerAddress;
  658.             end
  659.       End
  660.  Else begin
  661.       IF ReadPropertyValue(ServerName,OT_FILE_SERVER,'NET_ADDRESS',1,PropValue,moreSegments,propFlags)
  662.        then begin
  663.             result:=0;
  664.             Move(PropValue,ServAddr,SizeOf(TinternetworkAddress));
  665.             end
  666.        else begin
  667.             Result:=$FC;
  668.             AttachToFileServer:=False;
  669.             exit;
  670.             end;
  671.      End;
  672.  
  673. if result=0
  674.  then AttachToFileServerWithAddress(ServerName,ServAddr,ConnectionID);
  675.  
  676. AttachToFileServer:=(result=0);
  677. { Valid completion codes:
  678.   7C Maximum number of attached servers exceeded.
  679.   7D Bindery read error (The supplied server can't be located/doesn't exist)
  680.   F8 already attached to server;
  681.   F9 No Free connection slots at specified server;
  682.   FA no more server slots;
  683.   FE Server Bindery Locked;
  684.   FF No response from server
  685.   FC No Free slots in shells' ConnectionID table; }
  686. END;
  687.  
  688.  
  689. {F101 [2.0/2.1/3.x]}
  690. Function DetachFromFileServer( ConnectionID:Byte ):boolean;
  691. { removes server from shell's server table. Relinquishes the
  692.   fileserver connection number and breaks the connection.
  693.   The function will fail (result=$FF) if connID falls outside of the range [1..MaxServers].}
  694. Type ArrPtr=^Tarr;
  695.      Tarr=Array[0..MaxServers*48] of Byte;
  696. Var regs : TTregisters;
  697. begin
  698. if (ConnectionID<1) or (ConnectionID>MaxServers)
  699.  then result:=$FF
  700.  else begin
  701.       regs.ax := $F101;
  702.       regs.dl := ConnectionID; { 1..MaxServers }
  703.       RealModeIntr($21,regs);
  704.       result := regs.al;
  705.      { returncodes: 00 successful; FF Connection Doesn't exist }
  706.      end;
  707. DetachFromFileServer:=(result=0);
  708. end;
  709.  
  710.  
  711. {EF03 [2.0/2.1/3.x]}
  712. Function GetConnectionIDTable( ConnectionID: Byte ; Var TableEntry: TConnectionIDTableEntry ):boolean;
  713. { Returns a copy of the entry in the shells' ConnectionID table corresponding
  714.   With the given ConnectionID. All fields are returned lo-hi, except Net and Node
  715.   addresses.
  716.   The function will fail (result=$FF) if connID falls outside of the range [1..MaxServers].}
  717. Type ptarr=^tarr;
  718.      tarr=Array[0..MaxServers*32] of Byte;
  719. Var regs:TTregisters;
  720. begin
  721. If ((ConnectionID<1) or (ConnectionID>MaxServers))
  722.  then Result:=$FF
  723.  else begin
  724.       regs.ax:=$EF03;
  725.       RealModeIntr($21,regs);
  726.       move( ptarr(nwPtr(regs.es,regs.si))^[(ConnectionID-1)*32], TableEntry, 32 );
  727.       With TableEntry
  728.        do begin
  729.           ServerAddress.socket:=swap(ServerAddress.socket); { Force lo-hi }
  730.           ReceiveTimeOut:=swap(ReceiveTimeOut); { Force lo-hi }
  731.           MaxTimeOut:=swap(MaxTimeOut); { Force lo-hi }
  732.           WconnectionNumber:=swap(WconnectionNumber); { force lo-hi }
  733.           end;
  734.       Result:=$00;
  735.       end;
  736. GetConnectionIDTable:=(Result=0);
  737. end;
  738.  
  739.  
  740. {DC.. [2.0/2.1/3.x]}
  741. Function GetConnectionNumber(Var ConnectionNbr:byte):boolean;
  742. { returns connection number of requesting WS (1..100) }
  743. var regs:TTRegisters;
  744. begin
  745. regs.Ah:=$DC;
  746. RealModeIntr($21,regs);
  747. ConnectionNbr:=Regs.AL; { logical WS connection # }
  748. { cl= first digit of logical conn #, ch= second digit of conn# }
  749. result:=0;
  750. GetConnectionNumber:=true;
  751. end;
  752.  
  753.  
  754. {F217/16 [2.15c+]}
  755. Function GetConnectionInformation (ConnectionNbr:byte;
  756.                                    Var objName:String;
  757.                                    Var objType:Word;
  758.                                    Var objId:LongInt;
  759.                                    Var LoginTime:TnovTime ):boolean;
  760. Type TReq=Record
  761.           PacketLength  : Word;
  762.           FunctionVal   : Byte;
  763.           _ConnectionNo : Byte;
  764.           End;
  765.      Trep=Record
  766.           _objId        :LongInt;  { hi-lo }
  767.           _ObjType     : word;     { hi-lo }
  768.           _ObjName     : Array [1..48] of Byte;
  769.           _LoginTime    : TnovTime;
  770.           Reserved:word;
  771.           End;
  772.      TPreq=^Treq;
  773.      TPrep=^Trep;
  774. Var i,x: Integer;
  775. Begin
  776. With TPreq(GlobalReqBuf)^
  777. Do Begin
  778.    PacketLength := 2;
  779.    FunctionVal := $16;
  780.    _ConnectionNo := ConnectionNbr;
  781.    End;
  782. F2SystemCall($17,SizeOf(Treq),SizeOf(TRep),result);
  783. If Result = 0
  784.  Then Begin
  785.       With TPrep(GlobalReplyBuf)^
  786.       Do Begin
  787.          ZstrCopy(ObjName,_objName,48);
  788.          ObjId:=Lswap(_objId);
  789.          ObjType:=swap(_objType);
  790.          logintime:=_logintime;
  791.          End;
  792.       End;
  793. { patch to have a NIL object return an error. }
  794. if objName='' then result:=$FD; { no_such_connection }
  795. GetConnectionInformation:=(result=0);
  796. End { GetConnectInfo };
  797.  
  798.  
  799.  
  800. {F217/14 [2.15c+,unencrypted]}
  801. Function LoginToFileServer( objName:String; objType:word;
  802.                             password : string             ):boolean;
  803. Type Treq=record
  804.           len      :word;
  805.           subFunc  :byte;
  806.           _objType :Word; { hi-lo }
  807.           _objName :String[47]; { asciiz?  }
  808.           _objPassw:String[127]; { allowed to be '' }
  809.           end;
  810.      TPreq=^Treq;
  811. Begin
  812. WITH TPreq(GlobalReqBuf)^
  813. do begin
  814.    len:=SizeOf(Treq)-2;
  815.    subFunc:=$14;
  816.    _objType:=swap(objType);
  817.    PStrCopy(_objName,objName,47); _objName[47]:=#0; UpString(_objName);
  818.    PStrCopy(_objPassw,password,127); UpString(_objPassw);
  819.    end;
  820. F2SystemCall($17,SizeOf(Treq),0,result);
  821. LoginToFileServer:=(result=0)
  822. end;
  823.  
  824.  
  825. {F217/18 [3.x]}
  826. FUNCTION LoginEncrToFileServer(ObjName: String; ObjType: Word; PassWord: String): Boolean;
  827. { assumes the current effective server = the server to login to. }
  828.  
  829.  
  830.    FUNCTION LoginEncrypted(ObjName : String; ObjType : Word; VAR key : TencryptionKey): Boolean;
  831.    Type Treq=RECORD
  832.              BufLen  : Word;
  833.              _func   : Byte;
  834.              _key    : TencryptionKey;
  835.              _ObjType: Word;
  836.              _ObjName: String[48];
  837.              End;
  838.         TPreq=^Treq;
  839.    Begin
  840.    With TPreq(GlobalReqBuf)^
  841.     do Begin
  842.        _func := $18;
  843.        _key  := key;
  844.        _ObjType := Swap(objType);
  845.        PstrCopy(_ObjName,ObjName,48); UpString(_ObjName);
  846.        if ObjName[0]<#48
  847.          then _objName[0]:=objName[0]
  848.          else _objname[0]:=#48;
  849.        BufLen:=ord(_ObjName[0])+12;
  850.        End;
  851.    F2SystemCall($17,SizeOf(Treq),0,result);
  852.    LoginEncrypted:=(result=0);
  853.    End;
  854.  
  855. VAR
  856.   key : TencryptionKey;
  857.   ObjId:LongInt;
  858.  
  859. Begin
  860. UpString(password);
  861. if password[0]>#127
  862.  Then password[0]:=#127;
  863.  
  864. IF GetEncryptionKey(key)
  865.  Then Begin
  866.       IF GetBinderyObjectId(objName,objType,ObjId)
  867.        Then Begin
  868.             EncryptPassword(objId,password,key);
  869.             LoginEncrypted(ObjName, ObjType, key);
  870.             End;
  871.       End
  872.  Else LoginToFileServer(ObjName, ObjType, Password);
  873.  
  874. LoginEncrToFileServer:= (result=0);
  875. End;
  876.  
  877.  
  878. {F219 [2.15c+]}
  879. Function Logout:boolean;
  880. {logout from all file servers, remains attached to Server, effective EOJ }
  881. begin
  882.  F2SystemCall($19,0,0,result);
  883.  result:=$00;
  884.  Logout:=true;
  885. end;
  886.  
  887.  
  888. {F102 [2.0/2.1/3.x]}
  889. Function LogoutFromFileServer(var ConnectionID: byte):boolean;
  890. {logout from one file server}
  891. var regs : TTregisters;
  892. begin
  893.  regs.ah := $F1;
  894.  regs.al := $02;
  895.  regs.dl := ConnectionID;
  896.  RealModeIntr($21,regs);
  897.  result:=00;
  898.  LogoutFromFileServer:=True;
  899. end;
  900.  
  901. {EE.. [2.0/2.1/3.x]}
  902. FUNCTION GetWorkstationNodeAddress( var physicalNodeAddress: TNodeAddress ):boolean;
  903. { Get the physical station address (6 bytes hi-endian) }
  904. Var Regs              :TTRegisters;
  905. Begin
  906.  {Get the physical address from the Network Card}
  907.  Regs.Ah := $EE;
  908.  RealModeIntr($21,Regs);
  909.  result:=Regs.AL;
  910.  {nw node= CX BX AX hi-endian}
  911.  physicalNodeAddress[1]:=Regs.CH;
  912.  physicalNodeAddress[2]:=Regs.CL;
  913.  physicalNodeAddress[3]:=Regs.bh;
  914.  physicalNodeAddress[4]:=Regs.bl;
  915.  physicalNodeAddress[5]:=Regs.ah;
  916.  physicalNodeAddress[6]:=Regs.al;
  917.  result := 0;
  918.  GetWorkstationNodeAddress:=true;
  919. End;
  920.  
  921.  
  922. {F217/13 [2.15c+]}
  923. Function GetInternetAddress( ConnNbr : byte;
  924.                          Var IntNetAddress:TinterNetworkAddress
  925.                                                                ):boolean;
  926. Type  TReq=record
  927.            length      : word;
  928.            subfunction : byte;
  929.            connection  : byte;
  930.            end;
  931.       TRep=record
  932.            network : LongInt; { array [1..4] of byte } { hi-lo }
  933.            node    : array [1..6] of byte;             { hi-lo }
  934.            socket  : word; { array [1..2] of byte }    { hi-lo }
  935.            end;
  936.       TPreq=^Treq;
  937.       TPrep=^Trep;
  938. BEGIN
  939. With TPreq(GlobalreqBuf)^
  940. do begin
  941.    length := 2;
  942.    subfunction := $13;
  943.    connection := ConnNbr;
  944.    end;
  945. F2SystemCall($17,SizeOf(Treq),SizeOf(TRep),result);
  946. if result = 0
  947. then With TPrep(GlobalreplyBuf)^
  948.       do begin
  949.          move(network,IntNetAddress.net,4); {_is_ and stays hi-lo }
  950.          move(node,IntNetAddress.node,6);  { _is_ and stays hi-lo }
  951.          IntNetAddress.socket:=swap(socket);    { force lo-hi }
  952.          end;
  953. GetInternetAddress:=(result=0);
  954. end;
  955.  
  956. {D6.. [2.0/2.1/3.x]}
  957. FUNCTION EndOfJob(All : Boolean):boolean;
  958. { forces an end of job
  959.   If All is TRUE, then ends all jobs, otherwise ends a single job.
  960.   Ending a job unlocks and clears all locked or logged files and records.
  961.   It close all open network and local files and resets error and lock modes.
  962.   It also resets the workstation environment.                               }
  963. Var NovRegs:TTRegisters;
  964. BEGIN
  965. with NovRegs
  966. do begin
  967.    AH := $D6;
  968.    if All
  969.     then BX := $FFFF
  970.     else BX := $00;
  971.    end;
  972. RealModeIntr($21,NovRegs);
  973. Result:=$00;
  974. EndOfJob:=True;
  975. end;
  976.  
  977. {$IFDEF NewCalls}
  978.  
  979. {F218 [2.15c+]}
  980. FUNCTION EndOfJob(All : Boolean):boolean;
  981. { forces an end of job
  982.   If All is TRUE, then ends all jobs, otherwise ends a single job.
  983.   Ending a job unlocks and clears all locked or logged files and records.
  984.   It close all open network and local files and resets error and lock modes.
  985.   It also resets the workstation environment.                               }
  986. Type Treq=record
  987.           len:word;
  988.           _all:word;
  989.           end;
  990.           { ??? ERR: unclear how the req buffer should be... }
  991.      TPreq=^Treq;
  992. BEGIN
  993. With TPreq(GlobalReqBuf)^
  994.  do begin
  995.     if All
  996.      then _all := $FFFF
  997.      else _all := $0000;
  998.     len:=2;
  999.     end;
  1000. F2SystemCall($18,2,0,result);
  1001. Result:=$00;
  1002. EndOfJob:=True;
  1003. end;
  1004.  
  1005. {$ENDIF}
  1006.  
  1007.  
  1008. {F217/0A [2.0/2.1/3.x]}
  1009. Function EnterLoginArea( LoginSubDirName:String;
  1010.                          numberOfLocalDrives:Byte ):boolean;
  1011. { Changes the login directory. Used by boot-proms.
  1012.   LoginSubDirName contains the name of a sub directory under SYS:LOGIN
  1013.   (e.g. 'V330' means login.exe is to be executed in directory SYS:LOGIN\V330)}
  1014. Type Treq=record
  1015.           len:word;
  1016.           subFunc:byte;
  1017.           _numLocDr:Byte;
  1018.           _subDirName:String[255];
  1019.           end;
  1020.      TPreq=^Treq;
  1021. Begin
  1022. WITH TPreq(GlobalReqBuf)^
  1023. do begin
  1024.    len:=SizeOf(Treq)-2;
  1025.    subFunc:=$0A;
  1026.    _numLocDr:=numberOfLocalDrives;
  1027.    PstrCopy(_subDirName,LoginSubDirName,255); UpString(_subDirName);
  1028.    end;
  1029. F2SystemCall($17,Sizeof(Treq),0,result);
  1030. EnterLoginArea:=(result=0)
  1031. end;
  1032.  
  1033. {F217/15 [2.15c+]}
  1034. Function GetObjectConnectionNumbers( objName:String; objType:Word;
  1035.                                      Var numberOfConnections: Byte;
  1036.                                      Var connections: TconnectionList ):boolean;
  1037. { returns a list of connectionnumbers where objects of the desired type and
  1038.   name are logged in.
  1039.   Tconnectionlist is defined as an array[1..100] of byte. Max connections for
  1040.   Netware 286 = 100. Netware 386 allows more than 100 connections.
  1041.   If you pass a bad Objectname or the object is not logged in, the errorcode
  1042.   is NOT set to NO_SUCH_OBJECT ($FC), but GetObjectConnectionNumbers returns 0.}
  1043. Type Treq=record
  1044.           len:word;
  1045.           subFunc:byte;
  1046.           _objType:Word; { hi-lo}
  1047.           _objName:String[47];
  1048.           end;
  1049.      Trep=record
  1050.           _NbrOfConn:Byte;
  1051.           _connList:TconnectionList
  1052.           end;
  1053.      TPreq=^Treq;
  1054.      TPrep=^Trep;
  1055. Begin
  1056. WITH TPreq(GlobalReqBuf)^
  1057. do begin
  1058.    len:=SizeOf(Treq)-2;
  1059.    subFunc:=$15;
  1060.    PstrCopy(_objName,objName,47); _objname[47]:=#0; UpString(_objName);
  1061.    _objType:=swap(objType);
  1062.    end;
  1063. F2SystemCall($17,SizeOf(Treq),SizeOf(Trep),result);
  1064. With TPrep(GlobalReplyBuf)^
  1065. do begin
  1066.    connections:=_connList;
  1067.    NumberOfConnections:=_NbrOfConn;
  1068.    end;
  1069. getObjectConnectionNumbers:=(result=0)
  1070. end;
  1071.  
  1072.  
  1073. {EA00 [2.0/2.1/3.x]}
  1074. Function GetNetwareShellVersion( Var MajorVersion,MinorVersion,
  1075.                                      RevisionLevel :Byte       ):Boolean;
  1076. { Returns information about a WS environment. Queries shell.
  1077.   See also: GetWorkstationEnvironment                                   }
  1078.  
  1079. Var regs:TTRegisters;
  1080.     tmp1,tmp2:word;
  1081. Begin
  1082. With regs
  1083. do begin
  1084.    AX:=$EA00;
  1085.    GetGlobalBufferAddress(tmp1,tmp2,ES,DI);
  1086.    { Set ES:DI to real-mode address of GlobalReplyBuffer }
  1087.    { Returned value NOT used, but registers need a valid value anyway. }
  1088.    RealModeIntr($21,regs);
  1089.    MajorVersion:=BH;
  1090.    MinorVersion:=BL;
  1091.    { shell version>=3.00 : }
  1092.    { CH = Shell Type. 0=conventional, 1= expanded, 2= extended }
  1093.    RevisionLevel:=CL; { 1=A,2=B etc. }
  1094.    end;
  1095. Result:=$00;
  1096. GetNetwareShellVersion:=True;
  1097. end;
  1098.  
  1099. {EAxx,xx>00 [2.0/2.1/3.x] (shell version >=3.00) }
  1100. Function GetWorkstationEnvironment(Var OStype,OSversion,
  1101.                               HardwareType,ShortHWType:String):Boolean;
  1102. Type Treply=record
  1103.             stringz4:array[1..4*32] of char;
  1104.             end;
  1105.      TPreply=^Treply;
  1106. Var regs:TTRegisters;
  1107.     sNo,k:Byte;
  1108.     tmp1,tmp2:word;
  1109. Begin
  1110. With regs
  1111. do begin
  1112.    AX:=$EA01;
  1113.    BX:=$00;
  1114.    GetGlobalBufferAddress(tmp1,tmp2,ES,DI);
  1115.    { set ES:DI to real-mode address of GlobalReplyBuffer }
  1116.    RealModeIntr($21,regs);
  1117.    end;
  1118. OStype:='';
  1119. OSVersion:='';
  1120. HardwareType:='';
  1121. ShortHWtype:='';
  1122. sNo:=0;k:=0;
  1123. With TPreply(GlobalReplyBuf)^
  1124. do begin
  1125.    while sNo<4
  1126.    do begin
  1127.       inc(k);
  1128.       while ((k<128) and (stringz4[k]<>#0))
  1129.       do begin
  1130.          Case sNo of
  1131.           0:OStype:=OStype+stringz4[k];
  1132.           1:OSversion:=OSversion+stringz4[k];
  1133.           2:HardwareType:=HardwareType+stringz4[k];
  1134.           3:ShortHWtype:=ShortHWtype+stringz4[k];
  1135.          end; {case}
  1136.          inc(k);
  1137.          end;
  1138.       inc(Sno);
  1139.       end;
  1140.    end;
  1141. Result:=$00;
  1142. GetWorkstationEnvironment:=True;
  1143. end;
  1144.  
  1145. {DD.. [2.0/2.1/3.x]}
  1146. Function SetNetwareErrorMode( errMode:Byte):boolean;
  1147. { Sets the shell's handling mode for dealing with netware errors.
  1148.   0: default, INT 24 handler 'Abort, Retry, Fail';
  1149.   1: a netware error number is returned in AL;
  1150.   2: the netware error number is translated to a DOS error number,
  1151.      this number is returned.
  1152.   An EOJ resets the errormode to 0.                                      }
  1153. Var regs:TTregisters;
  1154. begin
  1155. Regs.AH:=$DD;
  1156. Regs.DL:=errMode;
  1157. RealModeIntr($21,Regs);
  1158. { regs.al now contains previous error mode }
  1159. Result:=$00;
  1160. SetNetWareErrorMode:=True;
  1161. end;
  1162.  
  1163. {DD.. [2.0/2.1/3.x]}
  1164. Function GetNetwareErrorMode(Var errMode:Byte):boolean;
  1165. Var regs:TTregisters;
  1166. begin
  1167. Regs.AH:=$DD;
  1168. Regs.DL:=0;
  1169. RealModeIntr($21,Regs);
  1170. { regs.al now contains previous error mode }
  1171. errMode:=regs.al;
  1172. regs.ah:=$DD;
  1173. RealModeIntr($21,regs); { reset old error mode }
  1174. Result:=$00;
  1175. GetNetWareErrorMode:=True;
  1176. end;
  1177.  
  1178.  
  1179.  
  1180. {BB.. [2.0/2.1/3.x]}
  1181. Function SetEndOfJobStatus( EndOfJobFlag: Boolean ):Boolean;
  1182. { When this function is called with EndOfJobFlag=False and control is returned
  1183.   to the root COMMAND.COM, COMMAND.COM will NOT perform an EOJ action.     }
  1184. Var regs:TTRegisters;
  1185. begin
  1186. regs.AH:=$BB;
  1187. If EndOfJobFlag
  1188.  then regs.AL:=$01
  1189.  else regs.AL:=$00;
  1190. RealModeIntr($21,Regs);
  1191. { AL now contains previous EOJ Flag }
  1192. Result:=$00;
  1193. SetEndOfJobStatus:=True;
  1194. end;
  1195.  
  1196. {BB.. [2.0/2.1/3.x]}
  1197. Function GetEndOfJobStatus(Var EndOfJobFlag: Boolean ):Boolean;
  1198. Var regs:TTRegisters;
  1199. begin
  1200. regs.AH:=$BB;
  1201. regs.al:=$00;
  1202. RealModeIntr($21,Regs);
  1203. { AL now contains previous EOJ Flag }
  1204. EndOfJobFlag:=(regs.al<>0);
  1205. regs.ah:=$BB;
  1206. RealModeIntr($21,regs); { reset old eoj-status }
  1207. Result:=$00;
  1208. GetEndOfJobStatus:=True;
  1209. end;
  1210.  
  1211. {E908 (shell 3.00+)}
  1212. Function SetShowDots( Show:Boolean):Boolean;
  1213. Var regs:TTregisters;
  1214. begin
  1215. regs.ax:=$E908;
  1216. if Show
  1217.  then regs.bl:=$01
  1218.  else regs.bl:=$00;
  1219. RealModeIntr($21,Regs);
  1220. Result:=$00;
  1221. SetShowDots:=True;
  1222. end;
  1223.  
  1224. {E908 (shell 3.00+)}
  1225. Function GetShowDots(Var Shown:Boolean):Boolean;
  1226. Var regs:TTregisters;
  1227. begin
  1228. regs.ax:=$E908;
  1229. RealModeIntr($21,Regs);
  1230. Shown:=(regs.bl<>0);
  1231. regs.ax:=$E908;
  1232. RealModeIntr($21,regs); {reset old 'show dots' parameter}
  1233. Result:=$00;
  1234. GetShowDots:=True;
  1235. end;
  1236.  
  1237. {DB.. [2.0/2.1/3.x]}
  1238. Function GetNumberOfLocalDrives( Var drives:Byte ):Boolean;
  1239. Var regs:TTregisters;
  1240. begin
  1241. regs.ah:=$DB;
  1242. RealModeIntr($21,Regs);
  1243. drives:=Regs.AL;
  1244. Result:=$00;
  1245. GetNumberOfLocalDrives:=TRUE;
  1246. end;
  1247.  
  1248.  
  1249. {=======SECONDARY FUNCTIONS===================================================}
  1250.  
  1251.  
  1252. {EF03 [2.0/2.1/3.x] secondary Function }
  1253. Function IsConnectionIDinUse( ConnectionID: Byte ):boolean;
  1254. { This function returns FALSE if connId isn't in the range [1..MaxServers] }
  1255. Type ptarr=^arr;
  1256.      arr=Array[0..MaxServers*32] of Byte;
  1257. Var regs:TTregisters;
  1258. begin
  1259. If ((ConnectionID<1) or (ConnectionID>MaxServers))
  1260.  then IsConnectionIDInUse:=FALSE { NWTP04: TRUE }
  1261.  else begin
  1262.       regs.ax:=$EF03;
  1263.       RealModeIntr($21,regs);
  1264.       IsConnectionIDinUse:=(ptarr(nwPtr(regs.es,regs.si))^[(ConnectionID-1)*32]
  1265.                             <> $00 )
  1266.       end;
  1267. end;
  1268.  
  1269. Function GetUserAtConnection( ConnectionNbr:byte; var username: string):boolean;
  1270. {This function provides a shorter method of obtaining just the USERID.}
  1271. var id:LongInt;
  1272.     typ:word;
  1273.     time:TnovTime;
  1274. begin
  1275.  getUserAtConnection:=GetConnectionInformation(ConnectionNbr,username,typ,id,time);
  1276. end;
  1277.  
  1278.  
  1279. Function GetEffectiveConnectionID(Var connId:byte):boolean;
  1280. begin
  1281. if NOT (GetPreferredConnectionID(connId) and (connId<>0))
  1282.  then if NOT (GetDefaultConnectionID(ConnId) and (connId<>0))
  1283.        then GetPrimaryConnectionID(ConnId);
  1284. GetEffectiveConnectionID:=(result=$00);
  1285. end;
  1286.  
  1287.  
  1288. Function GetObjectLoginControl(ObjName:string; ObjType:word;
  1289.                                VAR LoginControlInfo:TloginControl):boolean;
  1290. { Caller must have access to the bindery property LOGIN_CONTROL.
  1291.   Default: you need to be supervisor-equivalent or the object the property
  1292.            is associated with. (reading your 'own' information)
  1293.  
  1294.   PasswordcontrolFlag:
  1295.   00 User is allowed to change PW.
  1296.   01 User is NOT allowed to change PW.
  1297.   02 User is allowed to change PW, but the new password must be unique.
  1298.   03 User is NOT allowed to change PW, and a new password, to be changed
  1299.      by the supervisor, must be unique.
  1300. }
  1301. Var LCpropVal:Tproperty;
  1302.     lc:record
  1303.        _AccExpDate          :array[1..3] of byte; {yy mm dd}
  1304.        _AccDisabled         :boolean;
  1305.        _PWexpDate           :array[1..3] of byte; {yy mm dd}
  1306.        _GraceLoginsRemaining:byte;
  1307.        _DaysBetwPWchanges   :word; {hi-lo}
  1308.        _MaxGraceLogins      :byte;
  1309.        _minPWlen            :byte;
  1310.        _unknown1            :byte; {! = hi-byte of maxConcConn }
  1311.        _MaxConcConn         :byte;
  1312.        _loginTimes          :array[1..42] of byte;
  1313.        _LastLoginTime       :array[1..6] of byte; {yy mm dd hh mm ss}
  1314.        _PWcontrol           :byte;
  1315.        _unknown2            :byte; { not used }
  1316.        _MaxDiskSpace        :Longint; { hi-lo }
  1317.        _unknown3            :Byte; {! = hi-byte of bad login count }
  1318.        _badLoginCount       :byte;
  1319.        _AccountResetTime    :LongInt; { minutes since 1/1/1985 }
  1320.        _lastIntruderAddress :TinterNetworkAddress;
  1321.        end        ABSOLUTE LCpropVal;
  1322.     moreSegments:boolean;
  1323.     propFlags:byte;
  1324.  
  1325.     Procedure Min2NovTime(m:Longint; Var time:TnovTime);
  1326.     Const darr:array[1..12] of word=(0,31,59,90,120,151,181,212,243,273,304,334);
  1327.     Var d,dr:word;
  1328.         i,Lastleap:byte;
  1329.     begin
  1330.     d:=(m div 1440);
  1331.     i:=0;
  1332.     lastLeap:=84;
  1333.     while d>((3+(i*4))*365)+31+28
  1334.      do begin
  1335.         dec(d);
  1336.         lastLeap:=85+3+(i*4);
  1337.         inc(i);
  1338.         end;
  1339.     WITH time
  1340.      do begin
  1341.         year:=(d DIV 365)+85;
  1342.         dr:=(d MOD 365);
  1343.         month:=1;
  1344.         while (month<12) and (dr>darr[month+1]) do inc(month);
  1345.         day:=(dr-darr[month]);
  1346.         if (day=28) and (month=2) and (lastLeap=year)
  1347.          then inc(day);
  1348.         dr:=(m mod 1440);
  1349.         hour:=(dr div 60);
  1350.         min:=(dr mod 60);
  1351.         sec:=0;
  1352.         end;
  1353.     end;
  1354. begin
  1355. IF nwBindry.ReadPropertyValue(ObjName,ObjType,'LOGIN_CONTROL',1,
  1356.                               LCpropval,moreSegments,propFlags)
  1357.  then begin
  1358.       FillChar(LoginControlInfo,SizeOf(LoginControlInfo),#0);
  1359.       With LoginControlInfo
  1360.        do begin
  1361.           AccountDisabled           :=lc._AccDisabled;
  1362.           move(lc._AccExpDate[1],AccountExpirationDate.year,3);
  1363.           move(lc._PWexpDate[1],PasswordExpirationDate.year,3);
  1364.           MinimumPasswordLength     :=lc._minPWlen;
  1365.           PasswordControlFlag       :=lc._PWcontrol;
  1366.           DaysBetweenPasswordChanges:=swap(lc._DaysBetwPWchanges);
  1367.           Move(lc._lastLoginTime[1],LastLoginTime.year,6);
  1368.           GraceLoginsRemaining      :=lc._GraceLoginsRemaining;
  1369.           MaxGraceLoginsAllowed     :=lc._maxGraceLogins;
  1370.           BadLoginCount             :=lc._badLoginCount;
  1371.           Min2NovTime(Lswap(lc._AccountResetTime),AccountResetTime);
  1372.           LastIntruderAddress       :=lc._LastIntruderAddress;
  1373.           LastIntruderAddress.socket:=swap(LastIntruderAddress.socket); {force lo-hi}
  1374.           MaxConcurrentConnections  :=lc._MaxConcConn;
  1375.           Move(lc._LoginTimes[1],LoginTimes[1],42);
  1376.  
  1377.           DiskSpace                 :=Lswap(lc._MaxDiskSpace);
  1378.           end;
  1379.       result:=$00;
  1380.       end
  1381.  else result:=nwBindry.result;
  1382. GetObjectLoginControl:=(result=0);
  1383. end;
  1384.  
  1385. Function ObjectCanLoginAt(ObjName:String; ObjType:Word;
  1386.                           LoginTime:TnovTime            ):Boolean;
  1387. { Caller must have access to the bindery property LOGIN_CONTROL.
  1388.   Default: you need to be supervisor-equivalent or the object the property
  1389.            is associated with. (reading your 'own' information)
  1390.  
  1391.   -If one or more of the fields hour,min,sec,dayOfWeek contain a value >0,
  1392.    the supplied time will be checked against the login timerestrictions.
  1393.    (this means that checking '00:00 on sundays' is impossible)
  1394.   -If one or more of the fields year,month,day contain a value >0 , the
  1395.    date will be checked with the expiration date of the account and
  1396.    with the Account disabled Flag. }
  1397. Var CanLog:Boolean;
  1398.     Info:Tlogincontrol;
  1399.     half_hrs:word;
  1400. begin
  1401. IF GetObjectLoginControl(ObjName,ObjType,Info)
  1402.  then begin
  1403.       if (logintime.month>0) and (loginTime.day>0)
  1404.        then CanLog:=((NOT Info.AccountDisabled) and
  1405.                       IsLaterNovTime(Info.AccountExpirationDate,loginTime))
  1406.        else CanLog:=true;
  1407.       if (logintime.hour>0) or (loginTime.min>0)
  1408.          or (logintime.sec>0) or (logintime.DayOfWeek>0)
  1409.         then begin
  1410.              half_hrs:=(loginTime.DayOfWeek * 48)+(LoginTime.hour *2);
  1411.              if LoginTime.min>=30
  1412.               then inc(half_hrs);
  1413.              If half_hrs>=336
  1414.               then result:=$122
  1415.               else CanLog:=CanLog AND
  1416.                            ((Info.LoginTimes[(half_hrs DIV 8)+1]
  1417.                             AND (1 SHL (half_hrs MOD 8)) ) >0)
  1418.              end;
  1419.       end
  1420.  else begin
  1421.       CanLog:=(result=$FB); {no such property}
  1422.       result:=0;
  1423.       end;
  1424. ObjectCanLoginAt:=(result=0) and CanLog;
  1425. end;
  1426.  
  1427. Function GetObjectNodeControl( ObjName:string; ObjType:word;
  1428.                               {i/o} Var seqNbr:integer;
  1429.                               {out} Var NodeControlInfo:TnodeControl):boolean;
  1430. Var NCpropVal:Tproperty;
  1431.     moreSegments:boolean;
  1432.     propFlags:byte;
  1433. begin
  1434. if seqNbr=$FBFB
  1435.  then result:=$EC
  1436.  else begin
  1437.       if seqNbr<1 then seqNbr:=1;
  1438.       IF nwBindry.ReadPropertyValue(ObjName,ObjType,'NODE_CONTROL',seqNbr,
  1439.                                     NCpropval,moreSegments,propFlags)
  1440.        then begin
  1441.             Move(NCpropVal,NodeControlInfo,120);
  1442.             if moreSegments
  1443.              then inc(seqNbr)
  1444.              else seqNbr:=Integer($FBFB);
  1445.             end
  1446.        else result:=nwBindry.result;
  1447.       end;
  1448. GetObjectNodeControl:=(result=0);
  1449. { $EC No more records (no such segment);
  1450.   $FB No restrictions found (No such property) }
  1451. end;
  1452.  
  1453.  
  1454. end. { end of unit nwConn }
  1455.  
  1456.